<?php
include_once (DIR_BASE_SYS.'/lib/documentobject.class.php');

// {{{ class Document
/**
 * Document
 * 出力管理クラス
 * 
 * @author		risukan@hotmaill.com
 * @link		http://bouyke.com/
 */
class Document {
	/**
	 * 一度でもテンプレートを呼び出したか
	 */
	private $isLoaded;

	private $stopTemplate;

	private $Name;

	/**
	 * インデントの設定
	 */
	public $Indent;
	public $IndentCnt;

	public $sendStatusFlg;	// ステータスコード送信済みフラグ

	// MimeTypeの一覧
	private $MimeTypeList;


	public function __construct () {
		$this->isLoaded = false;

		$this->stopTemplate = false;

		$this->sendStatusFlg = false;

		$this->Indent = "\t";
		$this->IndentCnt = 0;
	}

	public function init () {
		Y('this.load+', YuTori::Create ($this, 'load'));
		Y('this.Object+', $DocumentRoot = DocumentObjectGroup::getAllDOMs()->DOG_appendChild ('html'));
		$DocumentRoot->Type = 'html';

		Y('this.Name+', YuTori::Create($this, 'Name'));
		Y('this.Status+', YuTori::Create($this, 'sendStatus'));
		Y('this.Direct+', YuTori::Create($this, 'Direct'));
		Y('this.TemplateOff+', YuTori::Create ($this, 'TemplateOff'));
	}

	/**
	 * 実際に出力する
	 */
	public function call ($Template = null) {
		if (!$this->stopTemplate){
			if ($this->Name && !$this->sendStatusFlg) {
				Y('Logger.Debug', 'Mime-Type判定 '.$this->Name);
				$Head = $this->getContentType ($this->Name);
				Y('Logger.Debug', '判定結果 '.$Head);
				header ($Head);
			}
	
			if (Y('Logger.Debug$')) Y('Logger.Debug', 'テンプレートメイン処理開始');
	
			if (!$this->isLoaded) {
				$this->load($Template);
			}
			
			$DOM = Y('this.Object$');
			if (is_scalar($DOM)) {
				print $DOM;
			} else {
				if (method_exists($this, 'output4'.$DOM->Type)) {
					$Method = 'output4'.$DOM->Type;
					$this->$Method ();
				}
				print $DOM->getChildren2Html("\t");
			}
		}

		// デバッグログの出力
		$DebugLevel = Y('App.Config.debugmode.level');

		// デバッグログのファイル出力
		if ($DebugLevel & 1) {
			if (!is_dir (DIR_BASE_SYS.'/vars/log')) mkdir (DIR_BASE_SYS.'/vars/log', 0777);

			$LogTxt = "######################################################################################".date('Y-m-d H:i:s')."\n";
			$LogTxt .= "処理時間:".Y('Logger.getTime')."sec.\n";
			$LogTxt .= "メモリ使用量:".Y('Logger.getMemory'). "byte\n";
			$LogTxt .= "メモリ使用量(peak):".Y('Logger.getMemoryPeak')."byte\n\n";

			foreach ((array)Y('Logger.getDebug') as $Log) {
				$LogTxt .= $Log['trace']."\n";
				$LogTxt .= trim($Log['txt'])."\n";
				$LogTxt .= $Log['time'].'sec. (+'.$Log['past'].'sec.)'."\n\n";
			}
			$LogTxt .= "######################################################################################\n\n";
			file_put_contents (DIR_BASE_SYS.'/vars/log/debuglog.txt', $LogTxt, FILE_APPEND);
		}

		// デバッグログのテンプレート出力
		if ($DebugLevel & 2) {
			if ((isset($Head) && preg_match('/text\/html/', $Head)) || !isset($Head)) {
				include_once (dirname(__FILE__).'/template/debuglog.php');
			}
		}

		return true;
	}


	public function load ($Target, $toObj = null) {
		if ($this->stopTemplate) return true;
		if (Y('Logger.Debug$')) Y('Logger.Debug', 'テンプレート取得開始:'.$Target);

		// toObjの生成
		if (is_null($toObj)) $toObj = Y('Document.Object$');

		// TemplateとModuleの分解
		$Target = explode (':', $Target, 2);
		if (count($Target) == 2) {
			$Module = $Target[0];
			$Template = ltrim($Target[1], '/');
		} else {
			$Module = null;
			$Template = ltrim($Target[0], '/');
		}
		if ($Template) {
			$Template = strtolower ($Template);
		} else {
			$Template = 'index';
		}

		$Class = 'tpl_'.str_replace ('/', '_', $Template);

		// すでに読み込み済みの場合
		if (class_exists($Class)) {
			$tplObj = new $Class ();
			return $tplObj->call($toObj);
		}

		$FilePath = DIR_BASE_SYS. '/app/template/'. $Template;
		if (is_dir ($FilePath)) $FilePath .= '/index';

		if (file_exists($FilePath.'.php')) {
		// Appディレクトリにテンプレートがある場合
			if (Y('Logger.Debug$')) Y('Logger.Debug', 'Appテンプレートを取得');
			require ($FilePath.'.php');
			$tplObj = new $Class ();
			$this->isLoaded = true;
			return $tplObj->call($toObj);
		} else {
			$Module = strtolower($Module);

			// モジュールパスの取得
			$FilePath = Y('Module.Path', $Module).'/template/'. $Template;
			if (is_dir ($FilePath)) $FilePath .= '/index';

			if (file_exists($FilePath.'.php')) {
				// 対象モジュールディレクトリにテンプレートがある場合
				if (Y('Logger.Debug$')) Y('Logger.Debug', 'モジュールテンプレートを取得');
				require ($FilePath.'.php');
				$tplObj = new $Class ();
				$this->isLoaded = true;
				return $tplObj->call($toObj);
			} else {
				if (Y('Logger.Debug$')) Y('Logger.Debug', 'テンプレート'.$FilePath.'が見つかりません');
				return false;
			}
		}
	}

	/**
	 * ステータスコードを送信する
	 */
	public function sendStatus ($Code) {
		if ($this->sendStatusFlg) {
			throw new YuToriException('ステータスコードを２度以上送信しようとしました。');
		}

		Y('Logger.Debug', 'ステータスコード送信');
		// ステータスコードファイルの探索
		$Dir = dirname(__FILE__).'/document/status/';
		$Args = func_get_args();
		$this->sendStatusArgs = array_slice ($Args, 1);
		if (file_exists($Dir.$Code.'.php')) {
			include ($Dir.$Code.'.php');
			unset ($this->sendStatusArgs);
			$this->sendStatusFlg = true;
			return true;
		} else {
			Y('Logger.Debug', 'ステータスファイル '.$Code.' が見つからない');
			unset ($this->sendStatusArgs);
			return false;
		}
	}

	/**
	 * テンプレート処理を行わないようにする
	 */
	public function TemplateOff () {
		Y('Logger.Debug', 'テンプレート処理OFF');
		$this->stopTemplate = true;
		return true;
	}

	/**
	 * 引数をダイレクトに出力する
	 */
	public function Direct ($String) {
		if ($this->Name && !$this->sendStatusFlg) {
			Y('Logger.Debug', 'Mime-Type判定 '.$this->Name);
			$Head = $this->getContentType ($this->Name);
			Y('Logger.Debug', '判定結果 '.$Head);
			header ($Head);
		}

		$this->isLoaded = true;
		print $String;
		return true;
	}

	/**
	 * 出力ファイル名をセットする
	 * 基本的に一度セットしたら変更されない。
	 * 第２引数にtrueを指定すれば強制的に変更される。
	 */
	public function Name ($Args) {
		return $this->setName ($Args, $this->Name);
	}
	private function setName ($FileName, &$Property = null, $ForceChange = false) {
		if ($ForceChange || !$Property) {
			$Property = $FileName;
		}
		return;
	}

	/**
	 * mimetypelist.iniの取得
	 */
	private function initMimeType () {
		if (file_exists (dirname(__FILE__). '/mimetypelist.ini')) {
			$this->MimeTypeList = parse_ini_file (dirname(__FILE__). '/mimetypelist.ini', false);
		} else {
			$this->MimeTypeList = null;
		}
		return;
	}

	/**
	 * mime-typeの判別
	 */
	private function getContentType ($Request) {
		if (empty($this->MimeTypeList)) $this->initMimeType();
		
		$Request = strtolower ($Request);

		if ($Ext = strrchr ($Request, '.')) {
			if (isset($this->MimeTypeList[$Ext])) {
				$Mime =$this->MimeTypeList[$Ext];
			} else {
				$Mime =$this->MimeTypeList['default'];
			}
		} else {
			$Mime =$this->MimeTypeList['default'];
		}
		if ($Mime == 'text/html' && eregi('application/xhtml\+xml',$_SERVER['HTTP_ACCEPT'])) {
			$Mime = 'application/xhtml+xml';
		}

		$Return = 'Content-Type: '.$Mime . '; charset="UTF-8"';

		return $Return;
	}

	/**
	 * 特定タイプの出力
	 */
	private function output4Html () {
		print ('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'."\n");
	}
	private function output4Xml () {
		// TODO: こういう書き方はよろしくない。
		print ('<?xml version="1.0" encoding="UTF-8"?>'."\n");
	}
}
// }}}
?>